// (C) Copyright to Kevin. Applied to MIT LICENSE

#pragma once

#include "CoreMinimal.h"

#include "Networking/NetworkingCommon.h"

#include "Runnable.h"
#include "RunnableThread.h"

#include "DateTime.h"

#include "Networking/Public/Networking.h"

#include "google/protobuf/message.h"

/**
 * 
 */
class BLOCKWORLD_API NetworkClient : public FRunnable
{
private:
	FRunnableThread* thread = NULL;

	FSocket* socket = NULL;

	bool connection_failed = false; // do not check by using this
	bool disconnected = false; // do not check by using this
	int64 connected_time = 0;
	int64 last_communicate_time = 0;

	TMap<uint32, const MessageHandler*> message_handlers;

	void InitializeHandlers();

public:
	static const uint32 MESSAGE_ID_UNKNOWN = 0xFFFFFFFF;

	FunctionPtr cb_on_connected = NULL;
	FunctionPtr cb_on_disconnected = NULL;
	FunctionPtr cb_on_connection_failed = NULL;
	FunctionPtr cb_on_timed_out = NULL;

	NetworkClient();
	~NetworkClient();

	void Start();

	// Inherited via FRunnable
	virtual uint32 Run() override;

	int GetConnectionState() ;

	void Shutdown();

	void SendMessage(const google::protobuf::Message& message);

	/* static void kcp_log(const char *log, struct IKCPCB *kcp, void *user) {
		TCHAR* txt = ANSI_TO_TCHAR(log);
		UE_LOG(URKNetworking, Log, *txt);
	} */

	static uint32 GetMessageID(const google::protobuf::Message& message);
	static google::protobuf::Message* CreateMessageByID(uint32 id, uint8* data, SIZE_T size);

};

class BLOCKWORLD_API MessageProcessTask : public IQueuedWork {
private:
	const MessageHandler* handler;
	google::protobuf::Message* message = NULL;
public:
	MessageProcessTask(const MessageHandler* handler, google::protobuf::Message* message);

	// Inherited via IQueuedWork
	virtual void DoThreadedWork() override;
	virtual void Abandon() override { };
};
